package my.mall.admin.api.config

import my.mall.common.annotation.Slf4j
import my.mall.common.annotation.Slf4j.Companion.log
import org.springframework.core.MethodParameter
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpInputMessage
import org.springframework.http.MediaType
import org.springframework.http.converter.HttpMessageConverter
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter
import java.io.*
import java.lang.reflect.Type
import java.nio.charset.StandardCharsets
import java.util.*

/**
 * @author fengbo
 * @since 2023/12/2 14:10
 */
@Slf4j //@RestControllerAdvice

class DecryptRequestBodyAdapter : RequestBodyAdviceAdapter() {
    /**
     * 该方法用于判断当前请求，是否要执行beforeBodyRead方法
     *
     * @param methodParameter handler方法的参数对象
     * @param targetType      handler方法的参数类型
     * @param converterType   将会使用到的Http消息转换器类类型
     * @return 返回true则会执行beforeBodyRead
     */
    override fun supports(
        methodParameter: MethodParameter,
        targetType: Type,
        converterType: Class<out HttpMessageConverter<*>>
    ): Boolean {
        return true
    }

    /**
     * 在Http消息转换器执转换之前执行
     *
     * @param inputMessage    客户端的请求数据
     * @param methodParameter handler方法的参数对象
     * @param targetType      handler方法的参数类型
     * @param converterType   将会使用到的Http消息转换器类类型
     * @return 返回 一个自定义的HttpInputMessage
     */
    @Throws(IOException::class)
    override fun beforeBodyRead(
        inputMessage: HttpInputMessage,
        methodParameter: MethodParameter,
        targetType: Type,
        converterType: Class<out HttpMessageConverter<*>>
    ): HttpInputMessage {

        // 读取加密的请求体
        val body = inputMessage.body
        val headers = inputMessage.headers
        val contentType = headers.contentType
        if (MediaType.APPLICATION_JSON != contentType && MediaType.APPLICATION_JSON_UTF8 != contentType) {
            return inputMessage
        }
        val contentLength = headers.contentLength.toInt()
        if (contentLength <= 0) {
            return inputMessage
        }
        headers.remove(HttpHeaders.CONTENT_LENGTH)
        val buff = ByteArray(contentLength)
        val readCnt = inputMessage.body.read(buff)
        if (readCnt <= 0) {
            return inputMessage
        }
        val bodyDec = String(buff, 0, readCnt, StandardCharsets.UTF_8)
        // 使用AES解密
//        JSONObject jsonObject = JSON.parseObject(bodyDec);
//        if (jsonObject.containsKey("SECURE_AES")) {
//            bodyDec = DESUtil.decode(jsonObject.getString("SECURE_AES"));
//        }
        headers.add(HttpHeaders.CONTENT_LENGTH, bodyDec.toByteArray(StandardCharsets.UTF_8).size.toString())
        val inputStream: InputStream = ByteArrayInputStream(bodyDec.toByteArray(StandardCharsets.UTF_8))
        return object : HttpInputMessage {
            override fun getHeaders(): HttpHeaders {
                return inputMessage.headers
            }

            override fun getBody(): InputStream {
                return inputStream
            }
        }
    }

    private fun getBodyString(inputStream: InputStream): String {
        val stringBuilder = StringBuilder()
        var bufferedReader: BufferedReader? = null
        try {
            if (Objects.nonNull(inputStream)) {
                bufferedReader = BufferedReader(InputStreamReader(inputStream))
                var bytesRead: Int
                val charBuffer = CharArray(1024)
                while (bufferedReader.read(charBuffer).also { bytesRead = it } != -1) {
                    stringBuilder.appendRange(charBuffer, 0, bytesRead)
                }
            }
        } catch (e: IOException) {
            log.error("get body fail，{}", e.message)
            throw RuntimeException(e)
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close()
                } catch (e: IOException) {
                    log.error("close stream fail，{}", e.message)
                }
            }
        }
        return stringBuilder.toString()
    }
}
